package cn.pconline.autoclub.web;

import cn.pconline.autoclub.config.SystemConfig;
import cn.pconline.autoclub.entity.CheckIn;
import cn.pconline.autoclub.entity.Club;
import cn.pconline.autoclub.entity.ClubIntegral;
import cn.pconline.autoclub.entity.ClubMember;
import cn.pconline.autoclub.entity.User;
import cn.pconline.autoclub.mq.SimpleMqClient;
import cn.pconline.autoclub.service.CheckInService;
import cn.pconline.autoclub.service.ClubService;
import cn.pconline.autoclub.service.GiftService;
import cn.pconline.autoclub.service.MemberService;
import cn.pconline.autoclub.service.UserService;
import cn.pconline.autoclub.util.EncodeUtils;
import cn.pconline.autoclub.util.JsonResult;
import cn.pconline.autoclub.util.Pager;
import cn.pconline.autoclub.util.WebUtils;
import cn.pconline.autoclub.util.WhoisUtil;
import cn.pconline.r.client.RequestCallback;
import cn.pconline.r.client.ResponseExtractor;
import cn.pconline.r.client.SimpleHttpTemplate;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.UnsupportedEncodingException;
import java.util.Date;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.math.NumberUtils;
import org.apache.commons.lang.time.DateUtils;
import org.apache.http.HttpResponse;
import org.apache.http.StatusLine;
import org.apache.http.client.methods.HttpUriRequest;
import org.apache.http.util.EntityUtils;
import org.gelivable.web.Env;
import org.gelivable.web.EnvUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;

/**
 *
 * @author wanganning
 */
@Controller
public class CheckInController {

    @Autowired
    private CheckInService checkInService;
    @Autowired
    private MemberService memberService;
    @Autowired
    private UserService userService;
    @Autowired
    private SystemConfig systemConfig;
    @Autowired
    private UserAuth userAuth;
    @Autowired
    private ClubService clubService;
    @Autowired
    private GiftService giftService;
    @Autowired
    SimpleHttpTemplate httpTemplate;
    @Autowired
    SimpleMqClient simpleMqClient;
    private String refererUri = "http://bbs.pcauto.com.cn/";
    private static final Logger log = LoggerFactory.getLogger(CheckInController.class);
    private static final int SOURCE_PC = 0;
    private static final int SOURCE_WAP = 1;

    @RequestMapping(value = "/checkIn", method = RequestMethod.POST)
    public void checkIn(HttpServletRequest request, HttpServletResponse response) throws IOException {
        WebUtils.setEncoding(request, response);
        User user = userAuth.getUser(request, response);
        long clubId = NumberUtils.toLong(request.getParameter("clubId"));
        String callback = WebUtils.param(request, "callback", "");
        int agent = WebUtils.paramInt(request, "agent", 0);//PC端签到
        int result = CheckInService.CHECKIN_FAILED;
        Club club = clubService.getNormalClub(clubId);
        String ip = WhoisUtil.getIp(request);
        if (user != null && user.getUid() > 0) {
            result = checkInService.doCheckIn(user.getUid(), clubId, ip, agent);
        }

        JsonResult jr;
        CheckIn checkIn = null;
        if (!memberService.isClubMember(user.getUid(), clubId)) {
            jr = new JsonResult(JsonResult.STATUS_AUTH_FAILED, "签到失败，只有该车友会会员才能签到哦！");
            log.error("checkIn failed log - userId:{},clubId: {},result:{}, "
                    + "common_session_id param:{}, userId param: {}"
                    + " cookie:{},User-Agent:{}",
                    user.getUid(), clubId, result,
                    request.getParameter("common_session_id"), request.getParameter("userId"),
                    request.getHeader("Cookie"), request.getHeader("User-Agent"));
        } else if (result == CheckInService.CHECKIN_SUCCESS) {
            checkIn = checkInService.getCheckInStatus(user.getUid(), clubId);//not null, created in doCheckIn()
            ClubIntegral i = checkInService.getCheckInIntegral(checkIn.getContinuousCheckIns(), agent);
            JSONObject jo = new JSONObject();
            jo.put("continuousCheckIns", checkIn.getContinuousCheckIns());
            jo.put("totalCheckIns", checkIn.getTotalCheckIns());
            jo.put("petrol", club == null ? 0 : i.getPetrol());
            String desc = jo.toString();
            jr = new JsonResult(JsonResult.STATUS_SUCCESS, desc);
            //签到成功才发消息到Mq
            JSONObject object = new JSONObject();
            object.put("userId", user.getUid());
            object.put("clubId", clubId);
            object.put("agent", agent);
            object.put("ip", ip);
            object.put("createAt", new Date(System.currentTimeMillis()));
            try {
                simpleMqClient.sendCheckinMessage(object);
            } catch (UnsupportedEncodingException ex) {
                log.error("Unsupported encoding for mq message.", ex);
            }
        } else if (result == CheckInService.CHECKIN_DUPLICATE) {
            jr = new JsonResult(JsonResult.STATUS_ILLEGAL_STATE, "请不要重复签到！");
            log.error("checkIn failed log - userId:{}, clubId:{} ,result:{}", user.getUid(), clubId, result);
        } else {
            jr = new JsonResult(JsonResult.STATUS_ERROR, "签到失败！");
            log.error("checkIn failed log - userId:{}, clubId:{} ,result:{}", user.getUid(), clubId, result);
        }
        try {
            PrintWriter print = response.getWriter();
            if (StringUtils.isNotBlank(callback)) {
                print.println(EncodeUtils.encodeForHTML(callback, 2) + "(" + jr.toString() + ")");
            } else {
                print.println(jr.toString());
            }
            print.flush();
            print.close();
        } catch (IOException ex) {
            log.error("签到失败", ex);
        }

        //同步签到信息到论坛,如果连接签到天数大于7天，传参数checkDays=7
        if (checkIn != null && result == CheckInService.CHECKIN_SUCCESS) {
            final long uid = user.getUid();
            final int checkDays = checkIn.getContinuousCheckIns() > 7 ? 7 : checkIn.getContinuousCheckIns();
            final HttpServletRequest req = request;
            new Thread(new Runnable() {
                @Override
                public void run() {
                    syncBbsCheckIn(uid, checkDays, req);
                }
            }).start();
        }
    }

    /**
     * 获取用户的签到信息
     *
     * @param request
     * @param response
     * @throws IOException
     */
    @RequestMapping(value = "/checkIn/stat", method = RequestMethod.GET)
    @ResponseBody
    public void checkStat(HttpServletRequest request, HttpServletResponse response) throws IOException {
        WebUtils.setEncoding(request, response);
        Env env = EnvUtils.getEnv();
        String callback = env.param("callback", "");
        long clubId = env.paramLong("clubId");
        String returnString;
        User user = userAuth.getUser(request, response);
        if (clubId <= 0 || user.getUid() <= 0) {
            returnString = new JsonResult(JsonResult.STATUS_AUTH_FAILED, "user & clubId required").toString();
            if (StringUtils.isBlank(callback)) {
                response.getWriter().println(returnString);
            } else {
                response.getWriter().println(EncodeUtils.encodeForHTML(callback, 2) + "(" + returnString + ")");
            }
            response.getWriter().close();
            return;
        }
        ClubMember member = memberService.findMember(user.getUid(), clubId);
        if (member == null) {
            returnString = new JsonResult(JsonResult.STATUS_ILLEGAL_STATE, "not a member").toString();
            if (StringUtils.isBlank(callback)) {
                response.getWriter().println(returnString);
            } else {
                response.getWriter().println(EncodeUtils.encodeForHTML(callback, 2) + "(" + returnString + ")");
            }
            response.getWriter().close();
            return;
        }

        CheckIn checkIn = checkInService.getCheckInStatus(user.getUid(), clubId);
        if (checkIn == null) {
            checkIn = checkInService.createCheckIn(user.getUid(), clubId);
        }
        String commonSessionId = cn.pconline.passport2.util.WebUtils.getCookie(request, systemConfig.getUserSessionName());
        long myCoin = giftService.getCoinsByUserId(commonSessionId, user.getUid());
        JSONObject jo = new JSONObject();
        jo.put("continuous", checkIn.getContinuousCheckIns());

        jo.put("myCoin", myCoin);
        jo.put("total", checkIn.getTotalCheckIns());
        jo.put("contribution", member.getPetrol());
        jo.put("rank", member.getRank());
        jo.put("hasCheckedInToday", checkIn.getLastCheckInAt() != null
                && DateUtils.isSameDay(new Date(), checkIn.getLastCheckInAt()));

        returnString = new JsonResult(JsonResult.STATUS_SUCCESS, jo.toJSONString()).toString();
        if (StringUtils.isNotBlank(callback)) {
            response.getWriter().println(EncodeUtils.encodeForHTML(callback, 2) + "(" + returnString + ")");
        } else {
            response.getWriter().println(returnString);
        }
        response.getWriter().close();
    }

    /**
     * 获取今天签到的人数
     *
     * @param request
     * @param response
     * @throws IOException
     */
    @RequestMapping(value = "/checkIn/getCheckToday", method = RequestMethod.GET)
    @ResponseBody
    public void getCheckToday(HttpServletRequest request, HttpServletResponse response) throws IOException {
        WebUtils.setEncoding(request, response);
        Env env = EnvUtils.getEnv();
        String callback = env.param("callback", "");
        long clubId = env.paramLong("clubId");
        int pageNo = env.paramInt("pageNo", 1);
        int pageSize = WebUtils.paramInt(request, "pageSize", 12, 1, 100);

        Pager<CheckIn> pager = checkInService.pagerForClubId(clubId, pageNo, pageSize);
        JSONObject json = this.Object2Json(pager);

        try {
            PrintWriter print = response.getWriter();
            if (StringUtils.isNotBlank(callback)) {
                print.println(EncodeUtils.encodeForHTML(callback, 2) + "(" + json.toJSONString() + ")");
            } else {
                print.println(json.toJSONString());
            }
            print.flush();
            print.close();
        } catch (IOException ex) {
            log.error("getCheckToday error.", ex);
        }
    }

    /**
     * pager转json
     *
     * @param pager
     * @return
     */
    private JSONObject Object2Json(Pager<CheckIn> pager) {
        JSONObject json = new JSONObject();
        JSONArray array = new JSONArray();
        if (pager.getResultList() == null || pager.getResultList().isEmpty()) {
            return json;
        } else {
            for (CheckIn checkIn : pager.getResultList()) {
                User user = userService.findUser(checkIn.getUid());
                if (user != null && user.getUid() > 0) {
                    JSONObject obj = new JSONObject();
                    long uid = user.getUid();
                    obj.put("nickname", user.getNickname());
                    obj.put("pic", WebUtils.face(uid, 50));
                    obj.put("url", systemConfig.getUcRoot() + "/" + uid + "/");
                    obj.put("uid", uid);
                    array.add(obj);
                }
            }
        }
        json.put("data", array);
        json.put("total", pager.getTotal());

        return json;
    }

    /**
     * 同步车友会签到到论坛
     *
     * @param uid
     * @param checkinDays
     */
    @Async
    public void syncBbsCheckIn(long uid, int checkinDays, HttpServletRequest request) {
        try {
            String comoonSession = cn.pconline.passport2.util.WebUtils.getCookie(request, systemConfig.getUserSessionName());
            StringBuilder url = new StringBuilder(300);
            String bbsUrl = systemConfig.getBbsRoot();
            url.append(bbsUrl).append("/plugin/pcpost/updateScore.ajax?");
            url.append("reason=clubCheckin&uid=").append(uid);
            url.append("&checkinDays=").append(checkinDays);
            url.append("&").append(systemConfig.getUserSessionName()).append("=").append(comoonSession);
            log.info("调用论坛接口：" + url.toString());

            String result = httpTemplate.post(url.toString(), refererUri,
                    new RequestCallback() {
                        @Override
                        public void doWithRequest(HttpUriRequest request) throws IOException {
                        }
                    },
                    new ResponseExtractor<String>() {
                        @Override
                        public String extractData(HttpResponse response) throws IOException {
                            StatusLine statusLine = response.getStatusLine();
                            if (statusLine.getStatusCode() == 200) {
                                return EntityUtils.toString(response.getEntity());
                            } else {
                                throw new IOException(statusLine.toString());
                            }
                        }
                    },
                    null);

            JSONObject json = null;
            if (StringUtils.isNotBlank(result)) {
                try {
                    json = JSONObject.parseObject(result.toString());
                    int status = json.getIntValue("status");
                    String desc = json.getString("desc");
                    if (status == 0) {
                        log.info("成功调用论坛接口:" + url.toString() + ",返回数据：" + desc);
                    } else {
                        log.info("调用论坛接口失败:" + url.toString() + ", 返回数据：" + desc);
                    }
                } catch (Exception e) {
                    log.error("格式化JSON失败,调用论坛接口：" + url.toString() + "- >" +result, e);
                }
            }
        } catch (Exception exception) {
            log.error("调用论坛签到接口失败！", exception);
            return;
        }
    }
    /**
     * 所有用户统一跳转签到页面接口
     * @param req
     * @param resp
     * @throws IOException 
     */
    @RequestMapping(value = "/checkIn/goToCheckIn", method = RequestMethod.GET)
    @ResponseBody
    public void goToCheckIn(HttpServletRequest req, HttpServletResponse resp) {
        int source = WebUtils.paramInt(req, "source", SOURCE_PC);
        User user = userAuth.getUser(req, resp);
        if (user == null || user.getUid() == 0) {
            if(source==SOURCE_PC){
                sendRedirect(resp, systemConfig.getUcRoot() + "/passport/login.jsp?return="+systemConfig.getRoot()+"/checkIn/goToCheckIn.do?"+req.getQueryString());
            }else{
                sendRedirect(resp, systemConfig.getUcWapRoot() + "/passport/login.jsp?return="+systemConfig.getRoot()+"/checkIn/goToCheckIn.do?"+req.getQueryString());
            }
            return ;
        }
        ClubMember clubMember = memberService.findClubMemberByUserId(user.getUid());
        if (clubMember == null) {
            if(source == SOURCE_PC){
                sendRedirect(resp, systemConfig.getRoot());
            }else{
                sendRedirect(resp, systemConfig.getWapRoot());
            }
             return ;
        }
        Club club = clubService.getValidClub(clubMember.getClubId());
        if(source==SOURCE_PC){
            String to = req.getParameter("to");
            String hash = "";
            if(to != null) {
                hash = "#"+to;
            }
            sendRedirect(resp, systemConfig.getRoot() + "/" + club.getClubUrl()+"/"+hash);
        }else{
            sendRedirect(resp, systemConfig.getWapRoot() + "/" + club.getClubUrl()+"/");
        }
         return ;
    }
    private void sendRedirect(HttpServletResponse resp, String url) {
        try {
            resp.sendRedirect(url);
            return;
        } catch (IOException ex) {
           log.error("重定向失败！", ex);
        }
    }
}
